{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<IBMBackend('ibm_kyiv')>\n"
     ]
    }
   ],
   "source": [
    "from qiskit_ibm_runtime import QiskitRuntimeService\n",
    "def get_token(file_path):\n",
    "    with open(file_path) as f:\n",
    "        data = f.read()\n",
    "    token = data.strip()\n",
    "    return token\n",
    "\n",
    "my_token = get_token(\"../docs/ibmq_tokens.txt\")\n",
    "service = QiskitRuntimeService(channel=\"ibm_quantum\", token=my_token)\n",
    " \n",
    "backend = service.least_busy(simulator=False, operational=True)\n",
    "print(backend)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Using IBM Quantum backend: <IBMBackend('ibm_kyiv')>\n",
      ">>> Job ID: cyfzt68cw2k00088xwj0\n"
     ]
    },
    {
     "ename": "TypeError",
     "evalue": "cannot unpack non-iterable NoneType object",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[2], line 14\u001b[0m\n\u001b[1;32m     11\u001b[0m num_sample \u001b[38;5;241m=\u001b[39m \u001b[38;5;241m100\u001b[39m\n\u001b[1;32m     13\u001b[0m mg \u001b[38;5;241m=\u001b[39m MoleculeGenerator(num_heavy_atom, backend_name\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mibmq\u001b[39m\u001b[38;5;124m\"\u001b[39m, remove_bond_disconnection\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m) \u001b[38;5;66;03m# qiskit_aer\u001b[39;00m\n\u001b[0;32m---> 14\u001b[0m smiles_dict, validity, diversity \u001b[38;5;241m=\u001b[39m mg\u001b[38;5;241m.\u001b[39msample_molecule(num_sample, random_seed \u001b[38;5;241m=\u001b[39m random_seed)\n\u001b[1;32m     15\u001b[0m \u001b[38;5;28mprint\u001b[39m(smiles_dict)\n\u001b[1;32m     16\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mValidity: \u001b[39m\u001b[38;5;132;01m{:.2f}\u001b[39;00m\u001b[38;5;124m%\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;241m.\u001b[39mformat(validity\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m100\u001b[39m))\n",
      "\u001b[0;31mTypeError\u001b[0m: cannot unpack non-iterable NoneType object"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "sys.path.append(\"../\")\n",
    "from qmg.generator import MoleculeGenerator\n",
    "from rdkit import RDLogger\n",
    "RDLogger.DisableLog('rdApp.*')\n",
    "\n",
    "# parameter settings for epoxide derivatives\n",
    "num_heavy_atom = 2\n",
    "random_seed = 9\n",
    "\n",
    "num_sample = 100\n",
    "\n",
    "mg = MoleculeGenerator(num_heavy_atom, backend_name=\"ibmq\", remove_bond_disconnection=False) # qiskit_aer\n",
    "\n",
    "# smiles_dict, validity, diversity = mg.sample_molecule(num_sample, random_seed = random_seed)\n",
    "# print(smiles_dict)\n",
    "# print(\"Validity: {:.2f}%\".format(validity*100))\n",
    "# print(\"Diversity: {:.2f}%\".format(diversity*100))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "       ┌────────────┐                                       ┌─┐              »\n",
      "q5_0: ─┤ Ry(1.4546) ├───■──────────────────────■────────────┤M├──────────────»\n",
      "       └───┬───┬────┘ ┌─┴─┐              ┌─────┴──────┐     └╥┘              »\n",
      "q5_1: ─────┤ X ├──────┤ X ├──────■───────┤ Ry(1.1728) ├──■───╫───────────────»\n",
      "      ┌────┴───┴────┐ └───┘┌─────┴──────┐└────────────┘┌─┴─┐ ║               »\n",
      "q5_2: ┤ Ry(0.43523) ├──────┤ Ry(2.7224) ├──────■───────┤ X ├─╫───────■───────»\n",
      "      ├─────────────┴┐     └────────────┘    ┌─┴─┐     └───┘ ║ ┌─────┴──────┐»\n",
      "q5_3: ┤ Ry(0.020216) ├───────────────────────┤ X ├───────────╫─┤ Ry(1.5795) ├»\n",
      "      └──────────────┘                       └───┘           ║ └────────────┘»\n",
      "q5_4: ───────────────────────────────────────────────────────╫───────────────»\n",
      "                                                             ║               »\n",
      "q5_5: ───────────────────────────────────────────────────────╫───────────────»\n",
      "                                                             ║               »\n",
      " c: 6/═══════════════════════════════════════════════════════╩═══════════════»\n",
      "                                                             0               »\n",
      "«                                                                             »\n",
      "«q5_0: ───────────────────────────────────────────────────────────────────────»\n",
      "«      ┌─┐                                                                    »\n",
      "«q5_1: ┤M├────────────────────────────────────────────────────────────────────»\n",
      "«      └╥┘┌─┐                                                                 »\n",
      "«q5_2: ─╫─┤M├─────────────────────────────────────────────────────────────────»\n",
      "«       ║ └╥┘┌─┐                                                              »\n",
      "«q5_3: ─╫──╫─┤M├──────────────────────────────────────────────────────────────»\n",
      "«       ║  ║ └╥┘┌────── ┌──────── ┌────────────┐                     ───────┐ »\n",
      "«q5_4: ─╫──╫──╫─┤       ┤         ┤ Ry(2.8221) ├──■─────────■───────        ├─»\n",
      "«       ║  ║  ║ │ If-0  │ Else-0  └───┬───┬────┘┌─┴─┐┌──────┴──────┐  End-0 │ »\n",
      "«q5_5: ─╫──╫──╫─┤       ┤         ────┤ X ├─────┤ X ├┤ Ry(0.25389) ├        ├─»\n",
      "«       ║  ║  ║ └──╥─── └────────     └───┘     └───┘└─────────────┘ ───────┘ »\n",
      "«       ║  ║  ║ ┌──╨──┐                                                       »\n",
      "« c: 6/═╩══╩══╩═╡ 0x0 ╞═══════════════════════════════════════════════════════»\n",
      "«       1  2  3 └─────┘                                                       »\n",
      "«            \n",
      "«q5_0: ──────\n",
      "«            \n",
      "«q5_1: ──────\n",
      "«            \n",
      "«q5_2: ──────\n",
      "«            \n",
      "«q5_3: ──────\n",
      "«      ┌─┐   \n",
      "«q5_4: ┤M├───\n",
      "«      └╥┘┌─┐\n",
      "«q5_5: ─╫─┤M├\n",
      "«       ║ └╥┘\n",
      "« c: 6/═╩══╩═\n",
      "«       4  5 \n"
     ]
    }
   ],
   "source": [
    "print(mg.qc)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "ename": "RuntimeJobFailureError",
     "evalue": "'Unable to retrieve job result. Error code 1500; Internal error. -- Try again or contact support. -- https://ibm.biz/error_codes#1500'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mRuntimeJobFailureError\u001b[0m                    Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[3], line 15\u001b[0m\n\u001b[1;32m      9\u001b[0m service \u001b[38;5;241m=\u001b[39m QiskitRuntimeService(\n\u001b[1;32m     10\u001b[0m     channel\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mibm_quantum\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m     11\u001b[0m     instance\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mibm-q/open/main\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m     12\u001b[0m     token\u001b[38;5;241m=\u001b[39mget_token(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m../docs/ibmq_tokens.txt\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m     13\u001b[0m )\n\u001b[1;32m     14\u001b[0m job \u001b[38;5;241m=\u001b[39m service\u001b[38;5;241m.\u001b[39mjob(\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mcyfzt68cw2k00088xwj0\u001b[39m\u001b[38;5;124m'\u001b[39m)\n\u001b[0;32m---> 15\u001b[0m job_result \u001b[38;5;241m=\u001b[39m job\u001b[38;5;241m.\u001b[39mresult()\n",
      "File \u001b[0;32m~/.conda/envs/qmg-n/lib/python3.12/site-packages/qiskit_ibm_runtime/runtime_job_v2.py:138\u001b[0m, in \u001b[0;36mRuntimeJobV2.result\u001b[0;34m(self, timeout, decoder)\u001b[0m\n\u001b[1;32m    136\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_reason_code \u001b[38;5;241m==\u001b[39m \u001b[38;5;241m1305\u001b[39m:\n\u001b[1;32m    137\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m RuntimeJobMaxTimeoutError(error_message)\n\u001b[0;32m--> 138\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m RuntimeJobFailureError(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUnable to retrieve job result. \u001b[39m\u001b[38;5;132;01m{\u001b[39;00merror_message\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m    139\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_status \u001b[38;5;241m==\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mCANCELLED\u001b[39m\u001b[38;5;124m\"\u001b[39m:\n\u001b[1;32m    140\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m RuntimeInvalidStateError(\n\u001b[1;32m    141\u001b[0m         \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mUnable to retrieve result for job \u001b[39m\u001b[38;5;132;01m{}\u001b[39;00m\u001b[38;5;124m. \u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mJob was cancelled.\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;241m.\u001b[39mformat(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mjob_id())\n\u001b[1;32m    142\u001b[0m     )\n",
      "\u001b[0;31mRuntimeJobFailureError\u001b[0m: 'Unable to retrieve job result. Error code 1500; Internal error. -- Try again or contact support. -- https://ibm.biz/error_codes#1500'"
     ]
    }
   ],
   "source": [
    "from qiskit_ibm_runtime import QiskitRuntimeService\n",
    "\n",
    "def get_token(file_path):\n",
    "    with open(file_path) as f:\n",
    "        data = f.read()\n",
    "    token = data.strip()\n",
    "    return token\n",
    "\n",
    "service = QiskitRuntimeService(\n",
    "    channel='ibm_quantum',\n",
    "    instance='ibm-q/open/main',\n",
    "    token=get_token(\"../docs/ibmq_tokens.txt\")\n",
    ")\n",
    "job = service.job('cyfzt68cw2k00088xwj0')\n",
    "job_result = job.result()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Using IBM Quantum backend: <IBMBackend('ibm_sherbrooke')>\n",
      "cwn8wd140e000089g3p0\n"
     ]
    }
   ],
   "source": [
    "from qiskit import QuantumCircuit, QuantumRegister, ClassicalRegister\n",
    "from qiskit.circuit.classical import expr\n",
    "from qiskit import generate_preset_pass_manager\n",
    "\n",
    "from qiskit_ibm_runtime import SamplerV2 as Sampler\n",
    "\n",
    "def get_dynamic_CNOT_circuit(num_qubit):\n",
    "    \"\"\"\n",
    "    (1) 1D chain of nearest neighbors\n",
    "    (2) 0th qubit is the control, and the last qubit (num_qubit-1) is the target\n",
    "    (3) The control qubit starts in the + state\n",
    "    \"\"\"\n",
    "    num_ancilla = num_qubit - 2\n",
    "    num_ancilla_pair = int(num_ancilla / 2)\n",
    "\n",
    "    qr = QuantumRegister(num_qubit)\n",
    "    cr1 = ClassicalRegister(num_ancilla_pair, name=\"cr1\") # The parity-controlled X gate\n",
    "    cr2 = ClassicalRegister(num_ancilla - num_ancilla_pair, name=\"cr2\") # The parity-controlled Z gate\n",
    "    cr3 = ClassicalRegister(2, name=\"cr3\") # For the final measurements on the control and target qubits\n",
    "    qc = QuantumCircuit(qr, cr1, cr2, cr3)\n",
    "\n",
    "    # Initialize the control qubit\n",
    "    qc.h(0)\n",
    "    qc.barrier()\n",
    "\n",
    "    # Entangle the contorl qubit and the first ancilla qubit\n",
    "    qc.cx(0,1)\n",
    "\n",
    "    # Create Bell pairs on ancilla qubits\n",
    "    # The first ancilla qubit in index 1\n",
    "    for i in range(num_ancilla_pair):\n",
    "        qc.h(2+2*i)\n",
    "        qc.cx(2+2*i, 2+2*i+1)\n",
    "\n",
    "    # Prepare Bell pairs on staggered ancilla and data qubits\n",
    "    for i in range(num_ancilla_pair+1):\n",
    "        qc.cx(1+2*i, 1+2*i+1)\n",
    "    for i in range(1, num_ancilla_pair+2):\n",
    "        qc.h(2*i-1)\n",
    "\n",
    "    # Measurement on alternating ancilla qubits starting with the first one\n",
    "    # Keep track of the parity for eventual conditional Z gate\n",
    "    for i in range(1, num_ancilla_pair+2):\n",
    "        qc.measure(2*i - 1, cr2[i-1])\n",
    "        if i == 1:\n",
    "            parity_control = expr.lift(cr2[i-1])\n",
    "        else:\n",
    "            parity_control = expr.bit_xor(cr2[i-1], parity_control)\n",
    "\n",
    "    # Measurement on staggered alternating ancilla qubits starting with the second\n",
    "    # Keep track of the parity of eventual conditional X gate\n",
    "    for i in range(num_ancilla_pair):\n",
    "        qc.measure(2*i + 2, cr1[i])\n",
    "        if i == 0:\n",
    "            parity_target = expr.lift(cr1[i])\n",
    "        else:\n",
    "            parity_target = expr.bit_xor(cr1[i], parity_target)\n",
    "\n",
    "    with qc.if_test(parity_control):\n",
    "        qc.z(0)\n",
    "\n",
    "    with qc.if_test(parity_target):\n",
    "        qc.x(-1)\n",
    "\n",
    "    # Final measurements on the control and target qubits\n",
    "    qc.measure(0, cr3[0])\n",
    "    qc.measure(-1, cr3[1])\n",
    "\n",
    "    return qc\n",
    "\n",
    "qc = get_dynamic_CNOT_circuit(num_qubit=7)\n",
    "\n",
    "my_token = get_token(\"../docs/ibmq_tokens.txt\")\n",
    "service = QiskitRuntimeService(channel=\"ibm_quantum\", token=my_token)\n",
    "backend = service.least_busy(simulator=False, operational=True)\n",
    "print(\"Using IBM Quantum backend:\", backend)\n",
    "pm = generate_preset_pass_manager(optimization_level=1, backend=backend)\n",
    "transpiled_qc = pm.run(qc)\n",
    "qc_transpiled_list = pm.run([transpiled_qc])\n",
    "\n",
    "sampler = Sampler(mode=backend)\n",
    "sampler.options.default_shots = 100\n",
    "\n",
    "job = sampler.run(qc_transpiled_list)\n",
    "print(job.job_id())"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "qmg-n",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.12.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
